﻿using System.Collections.Generic;
using System.Linq;
using SIG.Model;
using SIG.Repository;
using SIG.Infrastructure.Logging;
using SIG.Infrastructure.Cache;
using SIG.Infrastructure.Configs;
using SIG.Resources.Admin;
using System.Linq.Expressions;
using System;
using SIG.Basic.Extensions;

namespace SIG.Service
{
    public class CategoryService :  EntityService<Category>, ICategoryService
    {
       
        private readonly ICategoryRepository _categoryRepository;
        private readonly ILoggingService _loggingService;
        private readonly ICacheService _cacheService;

        public CategoryService(ICategoryRepository categoryRepository, ILoggingService loggingService, ICacheService cacheService)
            : base(categoryRepository, cacheService, loggingService)
        {           
            _categoryRepository = categoryRepository;
            _loggingService = loggingService;
            _cacheService = cacheService;
        }

        public List<Category> GetActiveCategories()
        {
            var key = $"{EntityNames.Category}_ACTIVE_ALL";
            if (!SettingsManager.Product.EnableCaching)
            {
                return ActiveCategories();
            }

            if (_cacheService.IsSet(key))
            {
                return (List<Category>)_cacheService.Get(key);

            }

            var categoryList = ActiveCategories();
            _cacheService.Set(key, categoryList, SettingsManager.Product.CacheDuration);


            return categoryList;
        }

        private List<Category> ActiveCategories()
        {
            return _categoryRepository.GetAllElements().Where(m => m.Active).OrderByDescending(m => m.Importance).ThenByDescending(m => m.CreatedDate).ToList();
        }

        public List<Category> GetCategories()
        {
            var key = $"{EntityNames.Category}_ALL";
            if (!SettingsManager.Product.EnableCaching)
            {
                return _categoryRepository.GetAllElements().OrderByDescending(m=>m.Importance).ThenByDescending(m=>m.CreatedDate).ToList();
            }

            if (_cacheService.IsSet(key))
            {
                return (List<Category>)_cacheService.Get(key);

            }

            var categoryList = _categoryRepository.GetAllElements().OrderByDescending(m => m.Importance).ThenByDescending(m => m.CreatedDate).ToList();
            _cacheService.Set(key, categoryList, SettingsManager.Product.CacheDuration);


            return categoryList;
        }
        public List<Category> GetCategoriesWithParent()
        {
            var key = $"{EntityNames.Category}_WITH_PARENT";
            if (!SettingsManager.Product.EnableCaching)
            {
                return _categoryRepository.GetFilteredElements(m => m.Id > 0, m => m.ParentCategory).ToList();
            }

            if (_cacheService.IsSet(key))
            {
                return (List<Category>)_cacheService.Get(key);

            }

            var categoryList = _categoryRepository.GetFilteredElements(m => m.Id > 0, m => m.ParentCategory).ToList();
            _cacheService.Set(key, categoryList, SettingsManager.Product.CacheDuration);

            return categoryList;
        }
        public Category GetCategoryBySeoName(string seoName)
        {
            var key = $"{EntityNames.Category}_bySeoName_{seoName}";

            if (!SettingsManager.Product.EnableCaching)
            {
                return GetCategory(seoName);
            }

            if (_cacheService.IsSet(key))
            {
                return (Category)_cacheService.Get(key);
            }

            var category = GetCategory(seoName);
            if (category!=null)
                _cacheService.Set(key, category, SettingsManager.Product.CacheDuration);


            return category;
        }

        private Category GetCategory(string seoName)
        {
            return _categoryRepository.GetFirstOrDefault(m => m.Active & m.SeoName.Equals(seoName, System.StringComparison.InvariantCultureIgnoreCase), m => m.Products);
        }

        public List<Category> GetPagedElements(int pageIndex, int pageSize, string keyword, out int totalCount)
        {

            //get list count
            var keyCount = $"{EntityNames.Category}_ListCount_{keyword}";

            var totalIQuery = _categoryRepository.GetAllElements().Where(g => g.Id>0);
            if (!string.IsNullOrEmpty(keyword))
                totalIQuery = totalIQuery.Where(g => g.Title.Contains(keyword));

            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(keyCount))
                {
                    totalCount = (int)_cacheService.Get(keyCount);
                }
                else
                {
                    totalCount = totalIQuery.Count();
                    _cacheService.Set(keyCount, totalCount, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                totalCount = totalIQuery.Count();
            }


            //get list
            var key = $"{EntityNames.Category}_CATEGORY_List_{pageIndex}_{pageSize}_{keyword}";

            List<Category> categories;
            Expression<Func<Category, bool>> filter = g => g.Id>0;
            Expression<Func<Category, bool>> filterByKeyword = g => g.Title.Contains(keyword);


            if (!string.IsNullOrEmpty(keyword))
                filter = filter.AndAlso(filterByKeyword);


            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(key))
                {
                    categories = (List<Category>)_cacheService.Get(key);
                }
                else
                {
                    categories = _categoryRepository.GetAllElements()
                        .Where(filter)
                        .OrderByDescending(m => m.Importance)
                        .ThenByDescending(m=>m.CreatedDate)
                        .Skip(pageSize * pageIndex)
                        .Take(pageSize).ToList(); 
                    //_categoryRepository.GetPagedElements(pageIndex, pageSize, (c => c.Importance), filter, false).ToList();
                    _cacheService.Set(key, categories, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                categories = _categoryRepository.GetAllElements().Where(filter)
                         .OrderByDescending(m => m.Importance)
                         .ThenByDescending(m => m.CreatedDate)
                         .Skip(pageSize * pageIndex)
                         .Take(pageSize).ToList();
            }

            return categories;

        }
        public List<Category> GetActivePagedElements(int pageIndex, int pageSize, string keyword, out int totalCount)
        {

            //get list count
            var keyCount = $"{EntityNames.Category}_ACTIVE_ListCount_{keyword}";

            var totalIQuery = _categoryRepository.GetAllElements().Where(g => g.Active);
            if (!string.IsNullOrEmpty(keyword))
                totalIQuery = totalIQuery.Where(g => g.Title.Contains(keyword));

            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(keyCount))
                {
                    totalCount = (int)_cacheService.Get(keyCount);
                }
                else
                {
                    totalCount = totalIQuery.Count();
                    _cacheService.Set(keyCount, totalCount, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                totalCount = totalIQuery.Count();
            }


            //get list
            var key = $"{EntityNames.Category}_ACTIVE_List_{pageIndex}_{pageSize}_{keyword}";

            List<Category> categories;
            Expression<Func<Category, bool>> filter = g => g.Active;
            Expression<Func<Category, bool>> filterByKeyword = g => g.Title.Contains(keyword);


            if (!string.IsNullOrEmpty(keyword))
                filter = filter.AndAlso(filterByKeyword);


            if (SettingsManager.Product.EnableCaching)
            {
                if (_cacheService.IsSet(key))
                {
                    categories = (List<Category>)_cacheService.Get(key);

                }
                else
                {
                    categories = _categoryRepository.GetPagedElements(pageIndex, pageSize, (c => c.Importance), filter, false,c=>c.ChildCategories).ToList();
                    _cacheService.Set(key, categories, SettingsManager.Product.CacheDuration);
                }
            }
            else
            {
                categories = _categoryRepository.GetPagedElements(pageIndex, pageSize, (c => c.Importance), filter, false, c => c.ChildCategories).ToList();
            }

            return categories;

        }


    }
}
